#include "YXNet.h"
#include "YXConstant.h"
#include "YXLog.h"

#if defined(__linux__)
#include "YXEpoll.c"
#elif defined(_WIN32) || defined(_WIN64)
#include "YXPoll.c"
#else
#error "Unsupported OS"
#endif


EventLoop *net_create_event_loop(int set_size) {
    EventLoop *event_loop;

    if ((event_loop = malloc(sizeof(EventLoop))) == NULL)
        goto err;
    if ((event_loop->events = malloc(sizeof(FileEvent) * set_size)) == NULL)
        goto err;
    if ((event_loop->fired_events = malloc(sizeof(FiredEvent) * set_size)) == NULL)
        goto err;

    // 初始化属性
    event_loop->set_size = set_size;
    // event_loop->max_fd = -1;
    event_loop->stop = 0;

    if (yxApiCreate(event_loop) == YX_ERR)
        goto err;

    // 初始化监听事件
    for (int i = 0; i < set_size; i++) {
        event_loop->events[i].mask = YX_NET_NONE;
    }

    return event_loop;

err:
    if (event_loop) {
        free(event_loop->events);
        free(event_loop->fired_events);
        free(event_loop);
    }
    return NULL;
}

void net_delete_event_loop(EventLoop *event_loop) {
    yxApiDelete(event_loop->api_data);
    free(event_loop->events);
    free(event_loop->fired_events);
    free(event_loop);
}

int net_create_file_event(EventLoop *event_loop, int fd, int mask, file_proc *proc, void *client_data) {
    if (fd >= event_loop->set_size)
        return YX_ERR;

    FileEvent *file_event = &event_loop->events[fd];

    // 监听事件
    if (yxApiAddEvent(event_loop, fd, mask) == YX_ERR)
        return YX_ERR;

    // 设置文件事件类型和事件处理器
    file_event->mask |= mask;
    if (mask & YX_NET_READABLE)
        file_event->read_proc = proc;
    if (mask & YX_NET_WRITABLE)
        file_event->write_proc = proc;

    // 私有数据
    file_event->client_data = client_data;

    return YX_OK;
}

void net_delete_file_event(EventLoop *event_loop, int fd, int mask) {
    if (fd >= event_loop->set_size)
        return;

    FileEvent *file_event = &event_loop->events[fd];

    if (mask == YX_NET_NONE)
        return;

    // 取消监听事件
    yxApiDelEvent(event_loop, fd, mask);

    file_event->mask &= ~mask;
}

#if defined(__linux__)
/**
 * 创建一个serversocket
 */
int net_create_server_socket(char *host, int port) {
    int                server_fd;
    struct sockaddr_in address;
    const int          opt = 1;

    // 创建socket文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        logFatalErrno();
    }

    // 设置socket为非阻塞模式
    if (net_set_non_block(server_fd) == YX_ERR) {
        logFatalErrno();
    }

    // 绑定socket到端口
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
        logFatalErrno();
    }
    if (setsockopt(server_fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt)) == -1) {
        logFatalErrno();
    }

    address.sin_family      = AF_INET;
    address.sin_addr.s_addr = inet_addr(host);
    address.sin_port        = htons(port);
    if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
        logFatalErrno();
    }

    // 监听
    // 第二个参数 backlog 指定内核应该为套接字排队的最大连接数。
    if (listen(server_fd, 10) == -1) {
        logFatalErrno();
    }

    log(YX_LOG_INFO, "The server will accept connections on: %s:%d...", host, port);
    return server_fd;
}

/**
 * 设置 fd 为非阻塞模式
 */
int net_set_non_block(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        logErrno();
        return YX_ERR;
    }

    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) == -1) {
        logErrno();
        return YX_ERR;
    }

    return YX_OK;
}

int net_tcp_non_block_connect(char *host, int port) {
    int                fd;
    struct sockaddr_in serv_addr;

    // 创建socket文件描述符
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        return YX_ERR;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port   = htons(port);
    // 将IPv4地址从文本转换为二进制形式
    if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
        close(fd);
        return YX_ERR;
    }

    // 连接到服务器
    if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        close(fd);
        // 处理错误
        return YX_ERR;
    }

    // 设置socket为非阻塞模式
    net_set_non_block(fd);

    return fd;
}

int net_wait(int fd, int mask, long long timeout) {
    struct pollfd pfd;
    int           retval, retmask = 0;

    memset(&pfd, 0, sizeof(pfd));

    pfd.fd = fd;
    if (mask & YX_NET_READABLE)
        pfd.events |= POLLIN;
    if (mask & YX_NET_WRITABLE)
        pfd.events |= POLLOUT;

    if ((retval = poll(&pfd, 1, timeout)) == 1) {
        if (pfd.revents & POLLIN)
            retmask |= YX_NET_READABLE;
        if (pfd.revents & POLLOUT)
            retmask |= YX_NET_WRITABLE;
        if (pfd.revents & POLLERR)
            retmask |= YX_NET_WRITABLE;
        if (pfd.revents & POLLHUP)
            retmask |= YX_NET_WRITABLE;
        return retmask;
    } else {
        return retval;
    }
}

#elif defined(_WIN32) || defined(_WIN64)
int net_create_server_socket(char *host, int port) {
    WSADATA            wsaData;
    struct sockaddr_in serverAddr;

    // 初始化Winsock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        logFatal("Winsock init failed");
    }

    // 创建套接字
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == INVALID_SOCKET) {
        logFatal("Socket creation failed");
    }

    // 设置服务器地址结构
    serverAddr.sin_family      = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port        = htons(port);

    // 绑定套接字
    if (bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        logFatal("Bind socket failed");
    }

    // 监听连接
    if (listen(serverSocket, 3) == SOCKET_ERROR) {
        logFatal("Listen failed");
    }

    log(YX_LOG_INFO, "The server will accept connections on: %s:%d...", host, port);
    return serverSocket;
}

int net_set_non_block(int fd) {
    // 设置套接字为非阻塞模式
    int iMode = 1;
    if (ioctlsocket(fd, FIONBIO, &iMode) == SOCKET_ERROR) {
        closesocket(fd);
        WSACleanup();
        return YX_ERR;
    }
    return YX_OK;
}
#endif
